package chapter3;
import java.util.ArrayList;

/**
 * 机器人抽象。给它一个迷宫和指令集，它会尝试导航到终点。
 * 
 * @author bkanber
 *
 */
public class Robot {
    //枚举类型，方向：北东南西
    private enum Direction {NORTH, EAST, SOUTH, WEST};

    //x坐标
    private int xPosition;
    //y坐标
    private int yPosition;
    //当前方向
    private Direction heading;
    //最大移动步数
    int maxMoves;
    //当前步数
    int moves;
    //传感器值
    private int sensorVal;
    //传感器列表
    private final int sensorActions[];
    //迷宫
    private Maze maze;
    //路径
    private ArrayList<int[]> route;
    
    /**
     * 初始化机器人
     * 
     * @param sensorActions 将传感器值映射到动作的字符串
     * @param maze 机器人使用的迷宫
     * @param maxMoves 机器人能移动的最大次数
     */
    public Robot(int[] sensorActions, Maze maze, int maxMoves){
        //计算传感器方向
        this.sensorActions = this.calcSensorActions(sensorActions);
        //迷宫
        this.maze = maze;
        //起始位置
        int startPos[] = this.maze.getStartPosition();
        //x坐标
        this.xPosition = startPos[0];
        //y坐标
        this.yPosition = startPos[1];
        //传感器值
        this.sensorVal = -1;
        //朝向 初始朝向东
        this.heading = Direction.EAST;
        //最大步数
        this.maxMoves = maxMoves;
        //当前步数
        this.moves = 0;
        //初始化路径
        this.route = new ArrayList<int[]>();
        //添加第一步
        this.route.add(startPos);
    }
    
    /**
     * 基于传感器输入运行机器人的动作
     */
    public void run(){
        while(true){            
            this.moves++;
            
            // 若下一个动作是停止，则跳出
            if (this.getNextAction() == 0) {
                return;
            }

            // 若当前位置到达目标点，则跳出
            if (this.maze.getPositionValue(this.xPosition, this.yPosition) == 4) {
                return;
            }
            
            // 若当前步数到达最大步数，则跳出
            if (this.moves > this.maxMoves) {
                return;
            }

            // 执行下一动作
            this.makeNextAction();
        }
    }
    
    /**
     * 将二进制数组转成10进制数组，每2位二进制转成一个十进制数
     * 如二进制的11对应10进制是3-->左转
     * 
     * @param sensorActionsStr 二元遗传算法染色体
     * @return int[] 将传感器值映射到动作的数组
     */
    private int[] calcSensorActions(int[] sensorActionsStr){
        // 有多少个动作？
        //数组长度=染色体长度=128 128/2=64，一共64个动作
        int numActions = (int) sensorActionsStr.length / 2;
        int sensorActions[] = new int[numActions];
        
        // Loop through actions
        for (int sensorValue = 0; sensorValue < numActions; sensorValue++){
            // Get sensor action
            int sensorAction = 0;
            if (sensorActionsStr[sensorValue*2] == 1){
                sensorAction += 2;
            }
            if (sensorActionsStr[(sensorValue*2)+1] == 1){
                sensorAction += 1;
            }
            
            // Add to sensor-action map
            sensorActions[sensorValue] = sensorAction;
        }
      
        return sensorActions;
    }
    
    /**
     * 执行下一个动作
     */
    public void makeNextAction(){
        // 若下一动作是前进 00->0 什么都不做，01->1前进 10 ->2右转 11 ->3左转
        // 注意代码里的左转和右转和书中3.3.2中描述的编码刚好是反的
        if (this.getNextAction() == 1) {
            int currentX = this.xPosition;
            int currentY = this.yPosition;
            
            // 根据当前方向进行操作，注意边界值
            //若当前方向朝北，前进则y坐标值减1
            if (Direction.NORTH == this.heading) {
                this.yPosition += -1;
                if (this.yPosition < 0) {
                    this.yPosition = 0;
                }
            }
            else if (Direction.EAST == this.heading) {
                this.xPosition += 1;
                if (this.xPosition > this.maze.getMaxX()) {
                    this.xPosition = this.maze.getMaxX();
                }
            }
            else if (Direction.SOUTH == this.heading) {
                this.yPosition += 1;
                if (this.yPosition > this.maze.getMaxY()) {
                    this.yPosition = this.maze.getMaxY();
                }
            }
            else if (Direction.WEST == this.heading) {
                this.xPosition += -1;
                if (this.xPosition < 0) {
                    this.xPosition = 0;
                }
            }
            
            // 若移动后的位置是墙，则不能移动
            if (this.maze.isWall(this.xPosition, this.yPosition) == true) {
                this.xPosition = currentX;
                this.yPosition = currentY;
            } 
            else {
                //不是墙，并且位置有变化，加到路径里
                if(currentX != this.xPosition || currentY != this.yPosition) {
                    this.route.add(this.getPosition());
                }
            }
        }
        // 顺时针 即右转
        else if(this.getNextAction() == 2) {
            //若当前方向是北，右转后方向改成东
            if (Direction.NORTH == this.heading) {
                this.heading = Direction.EAST;
            }
            else if (Direction.EAST == this.heading) {
                this.heading = Direction.SOUTH;
            }
            else if (Direction.SOUTH == this.heading) {
                this.heading = Direction.WEST;
            }
            else if (Direction.WEST == this.heading) {
                this.heading = Direction.NORTH;
            }
        }
        // 逆时针 即左转
        else if(this.getNextAction() == 3) {
            if (Direction.NORTH == this.heading) {
                this.heading = Direction.WEST;
            }
            else if (Direction.EAST == this.heading) {
                this.heading = Direction.NORTH;
            }
            else if (Direction.SOUTH == this.heading) {
                this.heading = Direction.EAST;
            }
            else if (Direction.WEST == this.heading) {
                this.heading = Direction.SOUTH;
            }
        }
        
        // 重置传感器的值
        this.sensorVal = -1;
    }
    
    /**
     * 根据传感器的值获得下一步动作
     * 
     * @return int 下一步动作
     */
    public int getNextAction() {
        return this.sensorActions[this.getSensorValue()];
    }
    
    /**
     * 获取传感器的值
     * 
     * @return int 下一个传感器的值
     */
    public int getSensorValue(){
        // 如果已经计算了传感器值，直接返回
        if (this.sensorVal > -1) {
            return this.sensorVal;
        }
                
		boolean frontSensor, frontLeftSensor, frontRightSensor, leftSensor, rightSensor, backSensor;
		frontSensor = frontLeftSensor = frontRightSensor = leftSensor = rightSensor = backSensor = false;

        // 查找那些传感器被激活
        //若当前朝向是北
        if (this.getHeading() == Direction.NORTH) {
            //前传感器，y坐标-1判断是否是墙，判断是否是墙的函数有容错，超出边界也是墙
            frontSensor = this.maze.isWall(this.xPosition, this.yPosition-1);
            frontLeftSensor = this.maze.isWall(this.xPosition-1, this.yPosition-1);
            frontRightSensor = this.maze.isWall(this.xPosition+1, this.yPosition-1);
            leftSensor = this.maze.isWall(this.xPosition-1, this.yPosition);
            rightSensor = this.maze.isWall(this.xPosition+1, this.yPosition);
            backSensor = this.maze.isWall(this.xPosition, this.yPosition+1);
        }
        else if (this.getHeading() == Direction.EAST) {
            frontSensor = this.maze.isWall(this.xPosition+1, this.yPosition);
            frontLeftSensor = this.maze.isWall(this.xPosition+1, this.yPosition-1);
            frontRightSensor = this.maze.isWall(this.xPosition+1, this.yPosition+1);
            leftSensor = this.maze.isWall(this.xPosition, this.yPosition-1);
            rightSensor = this.maze.isWall(this.xPosition, this.yPosition+1);
            backSensor = this.maze.isWall(this.xPosition-1, this.yPosition);
        }
        else if (this.getHeading() == Direction.SOUTH) {
            frontSensor = this.maze.isWall(this.xPosition, this.yPosition+1);
            frontLeftSensor = this.maze.isWall(this.xPosition+1, this.yPosition+1);
            frontRightSensor = this.maze.isWall(this.xPosition-1, this.yPosition+1);
            leftSensor = this.maze.isWall(this.xPosition+1, this.yPosition);
            rightSensor = this.maze.isWall(this.xPosition-1, this.yPosition);
            backSensor = this.maze.isWall(this.xPosition, this.yPosition-1);
        }
        else {
            frontSensor = this.maze.isWall(this.xPosition-1, this.yPosition);
            frontLeftSensor = this.maze.isWall(this.xPosition-1, this.yPosition+1);
            frontRightSensor = this.maze.isWall(this.xPosition-1, this.yPosition-1);
            leftSensor = this.maze.isWall(this.xPosition, this.yPosition+1);
            rightSensor = this.maze.isWall(this.xPosition, this.yPosition-1);
            backSensor = this.maze.isWall(this.xPosition+1, this.yPosition);
        }
                
        // 计算传感器的值，一共64种组合
        int sensorVal = 0;
        
        if (frontSensor == true) {
            sensorVal += 1;
        }
        if (frontLeftSensor == true) {
            sensorVal += 2;
        }
        if (frontRightSensor == true) {
            sensorVal += 4;
        }
        if (leftSensor == true) {
            sensorVal += 8;
        }
        if (rightSensor == true) {
            sensorVal += 16;
        }
        if (backSensor == true) {
            sensorVal += 32;
        }

        this.sensorVal = sensorVal;

        return sensorVal;
    }
    
    /**
     * 获取机器人的位置
     * 
     * @return int[] 返回机器人的坐标
     */
    public int[] getPosition(){
        return new int[]{this.xPosition, this.yPosition};
    }
    
    /**
     * 获取机器人的朝向
     * 
     * @return Direction 机器人的朝向
     */
    private Direction getHeading(){
        return this.heading;
    }
    
    /**
     * 返回机器人绕迷宫的完整路线
     * 
     * @return ArrayList<int> 机器人的路线
     */
    public ArrayList<int[]> getRoute(){       
        return this.route;
    }
    
    /**
     * 打印路线 一共128位
     * 
     * @return String 机器人的路线
     */
    public String printRoute(){
        String route = "";
        
        for (Object routeStep : this.route) {
            int step[] = (int[]) routeStep;
            route += "{" + step[0] + "," + step[1] + "}";
        }
        return route;
    }
}
